﻿using DiLe.Mes.Application.Common.Equipment;
using DiLe.Mes.Application.Local;
using DiLe.Mes.Model.Cloud.Dashboard.Statistics;
using DiLe.Mes.Model.Cloud.Statistics;
using DiLe.Mes.Model.Common.APP;
using DiLe.Mes.Model.Common.Equipment.Entity.Manage;
using EasyNetQ;
using MapleLeaf.Core.EventBus;
using Quartz;

namespace DiLe.Mes.Local.Jobs {
    /// <summary>
    /// 
    /// </summary>
    [DisallowConcurrentExecution]
    public class DataPushStatisticsJob : IJob {

        private readonly static IBus _ibus = AppHelper.GetService<IBus>();
        private readonly static LocalClient _localClient = AppHelper.GetService<LocalClient>();
        private readonly static EquipmentManageClient _equipmentManage = AppHelper.GetService<EquipmentManageClient>();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Execute(IJobExecutionContext context) {

            PushEquipmentStatistics("");

            PushEquipmentOutputStatistics("");
            await Task.Yield();
        }
        #region 设备运行时间统计
        /// <summary>
        /// 设备运行时间统计
        /// </summary>
        /// <param name="msg"></param>
        private static void PushEquipmentStatistics(string msg) {
            var where = Expressionable.Create<EquipmentOperationEntity>();
            DateTime currentDate = DateTime.Now.Date;
            if (DateTime.Now < currentDate.AddHours(8)) {
                currentDate = DateTime.Now.AddDays(-1).Date;
            }
            var starTime = currentDate.AddHours(7);
            var endTime = currentDate.AddDays(1).AddHours(8);
            where.And(p => p.CreateTime >= starTime);
            where.And(p => p.CreateTime <= endTime);

            var list = SqlSugarHelper.MasterDb.Queryable<EquipmentOperationEntity>().Where(where.ToExpression()).ToList();
            if (list.None()) {
                return;
            }
            var dataMap = list.GroupBy(x => x.DeviceNo).Select(x => (x.Key, x.OrderBy(y => y.CreateTime).ToList())).ToList();

            var pushDatas = new List<EquipmentStatisticsEntity>();
            foreach (var item in dataMap) {
                var dcount = item.Item2.Count(x => x.CreateTime <= currentDate.AddHours(19));
                var ncount = item.Item2.Count(x => x.CreateTime >= currentDate.AddHours(21).AddMinutes(-1));
                //日班
                EquipmentStatisticsEntity? dm = null;
                //夜班
                EquipmentStatisticsEntity? nm = null;
                if (dcount > 0 && ncount > 0) {
                    dm = GetDayEquipmentStatistics(item.Key, currentDate, item.Item2, false);
                    nm = GetNightEquipmentStatistics(item.Key, currentDate, item.Item2, false);
                } else if (dcount > 0) {
                    dm = GetDayEquipmentStatistics(item.Key, currentDate, item.Item2, true);
                } else if (ncount > 0) {
                    nm = GetNightEquipmentStatistics(item.Key, currentDate, item.Item2, true);
                }

                if (dm?.ActualWorkingHour > 0) {
                    pushDatas.Add(dm);
                }

                if (nm?.ActualWorkingHour > 0) {
                    pushDatas.Add(nm);
                }

            }
            var model = new MessageModel() {
                SendMsg = pushDatas.ToJosn(),
                MsgSign = "EquipmentStatistics"
            };
            _ibus.SendReceive.Send("data_push_statistics", model);

        }
        /// <summary>
        /// 日班
        /// </summary>
        /// <returns></returns>
        private static EquipmentStatisticsEntity GetDayEquipmentStatistics(string deviceno, DateTime date, List<EquipmentOperationEntity> list, bool iserror) {
            var dataList = new List<EquipmentStatisticsEntity>();
            var m1 = new EquipmentStatisticsEntity {//日班
                DeviceNo = deviceno,
                Date = date,
                Classes = "8:00~20:00",
                ActualWorkingHour = 0
            };
            DateTime start = date.AddHours(8).AddMinutes(-1);
            DateTime end = date.AddHours(20);
            if (iserror) {
                //7~21 误差60分钟
                start = date.AddHours(7);
                end = date.AddHours(21);
            }
            list = [.. list.Where(x => x.CreateTime > start && x.CreateTime <= end).OrderBy(t => t.CreateTime)];

            for (int i = 0; i < list.Count; i++) {
                var ism = list[i];
                if (i == 0) {
                    m1.EquipmentStartTime = ism.StartTime;
                }
                if (ism.StartTime < date.AddHours(8)) {
                    continue;
                }
                DateTime endtime;
                if (!ism.IsFinish || ism.EndTime == null) {
                    if (i == list.Count - 1) {
                        if (DateTime.Now >= date.AddHours(20)) {
                            endtime = date.AddHours(20);
                        } else {
                            endtime = DateTime.Now;
                        }
                    } else {
                        var nism = list[i + 1];
                        endtime = nism.StartTime;
                    }
                } else {
                    endtime = ism.EndTime.Value;
                }
                if (ism.EndTime > date.AddHours(20)) {
                    endtime = date.AddHours(20);
                }
                if (m1.EquipmentEndTime == null || m1.EquipmentEndTime < ism.EndTime) {
                    m1.EquipmentEndTime = ism.EndTime;
                }
                TimeSpan? ts = endtime - ism.StartTime;
                m1.ActualWorkingHour += (decimal)(ts?.TotalHours ?? 0);
            }
            if (m1.ActualWorkingHour > 12) {
                m1.ActualWorkingHour = 12;
            }
            return m1;
        }
        /// <summary>
        /// 夜班
        /// </summary>
        /// <returns></returns>
        private static EquipmentStatisticsEntity GetNightEquipmentStatistics(string deviceno, DateTime date, List<EquipmentOperationEntity> list, bool iserror) {
            var dataList = new List<EquipmentStatisticsEntity>();
            var m1 = new EquipmentStatisticsEntity {//日班
                DeviceNo = deviceno,
                Date = date,
                Classes = "20:00~8:00",
                ActualWorkingHour = 0
            };
            DateTime start = date.AddHours(20).AddMinutes(-1);
            DateTime end = date.AddHours(32);
            if (iserror) {
                //19~9 误差60分钟
                start = date.AddHours(19);
                end = date.AddHours(33);
            }
            list = [.. list.Where(x => x.CreateTime >= start && x.CreateTime <= end).OrderBy(t => t.CreateTime)];
            for (int i = 0; i < list.Count; i++) {
                var ism = list[i];
                if (i == 0) {
                    m1.EquipmentStartTime = ism.StartTime;
                }
                if (ism.StartTime < date.AddHours(20)) {
                    continue;
                }
                DateTime endtime;
                if (!ism.IsFinish || ism.EndTime == null) {
                    if (i == list.Count - 1) {
                        if (DateTime.Now <= date.AddHours(32)) {
                            endtime = date.AddHours(32);
                        } else {
                            endtime = DateTime.Now;
                        }
                    } else {
                        var nism = list[i + 1];
                        endtime = nism.StartTime;
                    }
                } else {
                    endtime = ism.EndTime.Value;
                }
                if (ism.EndTime > date.AddHours(32)) {
                    endtime = date.AddHours(32);
                }
                if (m1.EquipmentEndTime == null || m1.EquipmentEndTime < ism.EndTime) {
                    m1.EquipmentEndTime = ism.EndTime;
                }
                TimeSpan? ts = endtime - ism.StartTime;
                m1.ActualWorkingHour += (decimal)(ts?.TotalHours ?? 0);
            }

            if (m1.ActualWorkingHour > 12) {
                m1.ActualWorkingHour = 12;
            }
            return m1;
        }

        #endregion

        #region 设备产出
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static void PushEquipmentOutputStatistics(string msg) {
            var where = Expressionable.Create<EquipmentOperationEntity>();
            var currentDate = DateTime.Now.Date;
            if (DateTime.Now <= currentDate.AddHours(8)) {
                currentDate = DateTime.Now.AddDays(-1).Date;
            }
            var startDate = currentDate.AddHours(8);
            var endDate = currentDate.AddHours(32);
            where.And(p => p.OperationDateTime == currentDate);

            var eolist = SqlSugarHelper.MasterDb.Queryable<EquipmentOperationEntity>().Where(where.ToExpression()).ToList();
            if (eolist.None()) {
                return;
            }
            var infos = _equipmentManage.GetEquipmentInfoModelList();
            var list = _equipmentManage.GetEquipmentTypeList();
            var pushDatas = new List<EquipmentOutputStatisticsEntity>();
            foreach (var info in infos) {
                var items = eolist.Where(x => x.DeviceNo == info.EquipmentSign).OrderBy(x => x.CreateTime);
                if (items.None()) {
                    continue;
                }
                DateTime? start = items.FirstOrDefault()?.StartTime;
                if (start == null) {
                    continue;
                }
                if (start < startDate) {
                    start = startDate;
                }
                var m = new EquipmentOutputStatisticsEntity() {
                    EquipmentCode = info.EquipmentCode,
                    EquipmentName = info.EquipmentName,
                    Date = currentDate
                };
                var name = GetParentType(info.EquipmentTypeId, list);
                FillStartFormingTotalTimes(m, info.EquipmentSign, name, start.Value);

                DateTime? endtime = items.LastOrDefault()?.EndTime;
                if (endtime == null) {
                    FillEndFormingTotalTimes(m, info.EquipmentSign, name, DateTime.Now);
                } else if (endtime > endDate) {
                    FillEndFormingTotalTimes(m, info.EquipmentSign, name, endDate);
                } else {
                    FillEndFormingTotalTimes(m, info.EquipmentSign, name, endtime.Value);
                }
                pushDatas.Add(m);
            }
            if (pushDatas.None()) {
                return;
            }
            var model = new MessageModel() {
                SendMsg = pushDatas.ToJosn(),
                MsgSign = "EquipmentOutputStatistics"
            };
            _ibus.SendReceive.Send("data_push_statistics", model);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static void FillStartFormingTotalTimes(EquipmentOutputStatisticsEntity info, string sign, string name, DateTime dateTime) {
            switch (name) {
                case "成型机":
                    var data = _localClient.GetCurrentTimePointInfo(sign, dateTime);
                    info.StartMouldNumber = data?.FormingTotalTimes?.ToInt() ?? 0;
                    info.StartEnergy = data?.EeTotal?.ToInt();
                    break;
                case "AOI":
                    var dataAOI = _localClient.GetCurrentTimeAOIPointInfo(sign, dateTime);
                    info.StartNumber = dataAOI?.CheckTotalTimes?.ToInt() ?? 0;
                    info.StartCheckNG = dataAOI?.CheckNGNo?.ToInt() ?? 0;
                    break;
                case "切边机":
                case "冲切机":
                    var dataTrim = _localClient.GetCurrentTrimPointInfoList(sign, dateTime);
                    info.StartMouldNumber = dataTrim?.TrimingTotalTimes?.ToInt() ?? 0;
                    break;
                case "生产线":
                    var data1311 = _localClient.GetCurrent1311PointInfo(sign, dateTime);
                    info.StartMouldNumber = data1311?.FormingTotalTimes?.ToInt() ?? 0;
                    info.StartNumber = data1311?.StackingTotalNum?.ToInt() ?? 0;
                    info.StartEnergy = data1311?.EeTotal?.ToInt();
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private static void FillEndFormingTotalTimes(EquipmentOutputStatisticsEntity info, string sign, string name, DateTime dateTime) {
            switch (name) {
                case "成型机":
                    var data = _localClient.GetCurrentTimePointInfo(sign, dateTime);
                    info.EndMouldNumber = data?.FormingTotalTimes?.ToInt() ?? 0;
                    info.EndEnergy = data?.EeTotal?.ToInt();
                    break;
                case "AOI":
                    var dataAOI = _localClient.GetCurrentTimeAOIPointInfo(sign, dateTime);
                    info.EndNumber = dataAOI?.CheckTotalTimes?.ToInt() ?? 0;
                    info.EndCheckNG = dataAOI?.CheckNGNo?.ToInt() ?? 0;
                    break;
                case "切边机":
                case "冲切机":
                    var dataTrim = _localClient.GetCurrentTrimPointInfoList(sign, dateTime);
                    info.EndMouldNumber = dataTrim?.TrimingTotalTimes?.ToInt() ?? 0;
                    break;
                case "生产线":
                    var data1311 = _localClient.GetCurrent1311PointInfo(sign, dateTime);
                    info.EndMouldNumber = data1311?.FormingTotalTimes?.ToInt() ?? 0;
                    info.EndNumber = data1311?.StackingTotalNum?.ToInt() ?? 0;
                    info.EndEnergy = data1311?.EeTotal?.ToInt();
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeid"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        private static string GetParentType(long typeid, List<EquipmentTypeEntity> list) {
            string? name = "";
            var data = list.FirstOrDefault(p => p.Id == typeid);
            if (data?.ParentId != null && data?.ParentId > 0) {
                name = GetParentType(data.ParentId.Value, list);
            } else {
                name = data?.Name;
            }
            return name ?? "";
        }
        #endregion
    }
}
